#include "CStateMachine.h"
#include <assert.h>
#include "../core/CDirect3D.h"

/////////////////////////
#define NULL 0

CStateMachine* CStateMachine::m_pInstance = new CStateMachine();

CStateMachine::CStateMachine(void)
{
	m_pTopState = NULL;
}


CStateMachine::~CStateMachine(void)
{
}

CStateMachine* CStateMachine::GetInstance()
{
	return m_pInstance;
}
void CStateMachine::FreeInstance()
{
	assert(m_pInstance != NULL && "Instance already free!");
	delete m_pInstance;
}


void CStateMachine::Initialize()
{

}

void CStateMachine::Shutdown()
{
}

void CStateMachine::PushState(IBaseState* pState)
{
	assert(pState != NULL && "you cannot pass a NULL state!");

	// create the state object
	StateObject* pNewState = new StateObject();
	pNewState->pState = pState;
	pNewState->pNext = m_pTopState;
	m_pTopState = pNewState;

	// enter new state
	m_pTopState->pState->Enter();
}

void CStateMachine::ChangeState(IBaseState* pState)
{
	FlushStates();
	PushState(pState);
}

void CStateMachine::FlushStates()
{
	StateObject* pCurState = NULL;
	while(m_pTopState != NULL)
	{
		m_pTopState->pState->Exit();
		delete m_pTopState->pState;
		pCurState = m_pTopState->pNext;
		delete m_pTopState;
		m_pTopState = pCurState;
	}

	assert(m_pTopState == NULL && "The Top state should be NULL! Something Went Wrong!");
}

void CStateMachine::PopState()
{
	assert(m_pTopState != NULL && "There are no States to POP! Rethink your design or use FlushStates()");

	IBaseState* pState = m_pTopState->pState;
	StateObject* pStateObject = m_pTopState->pNext;
	delete m_pTopState;
	m_pTopState = pStateObject;
	pState->Exit();
	delete pState;
}

void CStateMachine::Update(float fDeltaTime)
{
	m_pTopState->pState->Update(fDeltaTime);
	/*
	StateObject* pCurState = m_pTopState;
	while(pCurState != NULL)
	{
		pCurState->pState->Update(fDeltaTime);
		pCurState = pCurState->pNext;
	}
	*/
}

void CStateMachine::Input(CRetroInput* pInput)
{
	m_pTopState->pState->Input(pInput);
	/*
	StateObject* pCurState = m_pTopState;
	while(pCurState != NULL)
	{
		pCurState->pState->Input(pInput);
		pCurState = pCurState->pNext;
	}
	*/
}

void CStateMachine::Render(CDirect3D* pRender)
{
	StateObject* pCurState = m_pTopState;
	while(pCurState != NULL)
	{
		pCurState->pState->Render(pRender);
		pCurState = pCurState->pNext;
	}
}
